defmodule Pango.DeeprPsql do
	@moduledoc false
	alias Pango.PgSqlLib
	import UserLib
	import ErrCode
	require Logger

	def list(
				caller_mod,
				user,
				object,
				args = %{"total_page" => total_page, "[]" => page, "()" => where, "=>" => select},
				query_params
			) do
		(is_integer(page) && page >= 0) || page == false ||
			PrivateCandy.debug_remind(__ENV__, "page 类型错误, 只能为 false or 整数")
		mod = caller_mod.get_db_mod(object)
		where = case Map.get(args, "OrderBy") do
			nil ->
				where
			order_by ->
				Map.put(where, "OrderBy", order_by)
		end
		list_sql2(
			get_project_id(user),
			mod,
			page,
			object,
			select,
			where,
			total_page,
			query_params,
			Map.get(args, "args", %{})
		)
	end
	def list(_, _, _, args, _) do
		PrivateCandy.debug_remind(__ENV__, "deepr list not match #{inspect(args)}")
	end


	def info(caller_mod, user, object, %{"()" => where, "=>" => select} = args, query_params) do
		mod = caller_mod.get_db_mod(object)
		info_sql(get_project_id(user), mod, object, select, where, query_params)
	end
	def info(_, _, _, _, _) do
		PrivateCandy.debug_remind(__ENV__, "deepr info not match")
	end


	@doc """
	WITH res AS(SELECT uid,id,info FROM "test_slab".notice   WHERE info->>'a' = 'b'),
	res2 AS(SELECT uid,id,info FROM "test_slab".notice   WHERE info->>'a' = 'b'),
	count_cte AS (SELECT count(*) AS total_count FROM res2),
	count_cte2 AS (SELECT count(*) AS total_count FROM res2)
	SELECT 'notice', 'list',
	    (SELECT total_count FROM count_cte) as t1, (select array_to_json(array_agg(row_to_json(res))) from res),
	    'notice2', 'list2',
	    (SELECT total_count FROM count_cte) as t2, (select array_to_json(array_agg(row_to_json(res2))) from res2)
	"""
	def list_sql2(prefix, mod, page1, object, select, where, total_page, query_params, query_args) do
		fields = mod.fields()
		{from, where} = case Map.pop(where, "from") do
			{nil, where} ->
				{"", where}
			{from, where} ->
				{", " <> from, where}
		end
		table = mod.get_table()
		select = Enum.map_join(
			select,
			",",
			fn (f) ->
				case Map.get(fields, f) do
					%{mfa: {m, fun, a}} ->
						apply(m, fun, [:select, query_args, f | a])
					nil ->
						PrivateCandy.debug_remind(__ENV__, "lack #{f} 字段")
					_ ->
						f
				end
			end
		)
		size = AppConfigure.fetch(:page_size)
		page = if page1 == false do
			" LIMIT 200"
		else
			skip = (page1 - 1) * size
			" LIMIT #{size} OFFSET #{skip} "
		end
		table_res = table <> "_res"
		count__res = table <> "_count_cte"
		Process.put(:prefix, prefix)
		{where, params_acc} = Pango.DeeprPgFilter.where(where, fields, query_params)
		Process.delete(:prefix)
		#		if page1 == 1 && total_page do
		if true do
			with = """
			#{table_res} AS(
			   SELECT #{select} FROM #{PsqlLib.get_table(prefix, mod)} #{from}
			   #{where}
			),
			#{count__res} AS(
			    SELECT count(*) AS total_count FROM #{table_res}
			)
			"""
			return = """
			'#{object}', 'list', #{page1} as page, (select * from #{count__res}),
			(SELECT (total_count + #{size} - 1) / #{size} FROM #{count__res}),
			(SELECT array_to_json(array_agg(row_to_json(t))) FROM (SELECT * FROM #{table_res} #{page}) t)
			"""
			{with, return, params_acc}
		else
			with =
				"""
				#{table_res} AS(
				    SELECT #{select} FROM #{PsqlLib.get_table(prefix, mod)} #{from}
				    #{where} #{page}
				)
				"""
			return = """
			'#{object}', 'list', #{page1} as page, null AS total_page, null AS total_count,
			(SELECT array_to_json(array_agg(row_to_json(t))) FROM (SELECT * FROM #{table_res}) t)
			"""
			{with, return, params_acc}
		end
	end

	def info_sql(prefix, mod, object, select, where, query_params) do
		fields = mod.fields()
		{from, where} = case Map.pop(where, "from") do
			{nil, where} ->
				{"", where}
			{from, where} ->
				{", " <> from, where}
		end
		{where, params_acc} = Pango.DeeprPgFilter.where(where, fields, query_params)
		select = Enum.join(select, ",")
		table = mod.get_table()
		{
			"SELECT '#{object}', 'info', array_to_json(array_agg(row_to_json(#{table}))) FROM ( SELECT "
			<> select <> " FROM " <> PsqlLib.get_table(prefix, mod) <> from
			<> where <> " limit 1) AS #{table} ",
			params_acc
		}
	end

	def query(caller_mod, user, object, args, repo \\ nil) do
		repo = case repo do
			nil ->
				caller_mod.default_repo()
			v ->
				v
		end
		{with, return, {_, pg_params_acc}} = list(caller_mod, user, object, args, {1, []})
		sql = """
		with #{with}
		select #{return}
		"""
		Pango.DeeprList.psql_execute(sql, repo, Enum.reverse(pg_params_acc), user, caller_mod, [], %{})
	end


end
